package com.yw.android.common.filelogger;

import android.util.Log;

public class LogCollecter {
    /**
     * 日志级别定义
     */
    public final static int ERROR = 0;     // 错误级别
    public final static int WARN = 1;     // 警告级别
    public final static int INFO = 2;     // 一般级别
    public final static int DEBUG = 3;     // 调试级别
    public final static int TRACE = 4;     // 跟踪级别

    /**
     * 日志追加对象
     */
    private Appender appender = null;

    /**
     * 日志级别，默认是INFO级别
     */
    private int level = DEBUG;

    /**
     * 获取日志追加对象
     *
     * @return 日志追加对象
     */
    public Appender getAppender() {
        return appender;
    }

    /**
     * 初始化日志
     *
     * @param appender 日志追加对象
     */
    public synchronized LogCollecter setAppender(Appender appender) {
        this.appender = appender;
        if (null != this.appender) {
            this.appender.setLogLevel(level);
        }

        return this;
    }

    /**
     * 获取当前的日志级别
     *
     * @return 当前的日志级别
     */
    public int getLogLevel() {
        return level;
    }

    /**
     * 设置日志级别
     *
     * @param newLevel 设置的日志级别
     * @return 当前对象
     */
    public synchronized LogCollecter setLogLevel(int newLevel) {
        this.level = newLevel;
        if (null != appender) {
            appender.setLogLevel(level);
        }

        return this;
    }

    /**
     * ERROR: Error message
     *
     * @param msg the message to be logged
     * @param obj the object that send error message
     */
    public void error(Object obj, String msg) {
        writeLogMessage(obj.getClass().getName(), ERROR, msg);
    }

    /**
     * ERROR: Error message
     *
     * @param msg the message to be logged
     * @param tag the tag characterizing the log message initiator
     */
    public void error(String tag, String msg) {
        writeLogMessage(tag, ERROR, msg);
    }

    /**
     * ERROR: Error message
     *
     * @param obj the object that send log message
     * @param msg the message to be logged
     * @param t   the exception that caused the error
     */
    public void error(Object obj, String msg, Throwable t) {
        writeLogMessage(obj.getClass().getName(), ERROR, msg, t);
    }

    /**
     * ERROR: Error message
     *
     * @param tag the tag characterizing the log message initiator
     * @param msg the message to be logged
     * @param t   the exception that caused the error
     */
    public void error(String tag, String msg, Throwable t) {
        writeLogMessage(tag, ERROR, msg, t);
    }

    /**
     * WARN: Information message
     *
     * @param obj the object that send log message
     * @param msg the message to be logged
     */
    public void warn(Object obj, String msg) {
        writeLogMessage(obj.getClass().getName(), WARN, msg);
    }

    /**
     * WARN: Information message
     *
     * @param tag the tag characterizing the log message initiator
     * @param msg the message to be logged
     */
    public void warn(String tag, String msg) {
        writeLogMessage(tag, WARN, msg);
    }

    /**
     * INFO: Information message
     *
     * @param obj the object that send log message
     * @param msg the message to be logged
     */
    public void info(Object obj, String msg) {
        writeLogMessage(obj.getClass().getName(), INFO, msg);
    }

    /**
     * INFO: Information message
     *
     * @param tag the tag characterizing the log message initiator
     * @param msg the message to be logged
     */
    public void info(String tag, String msg) {
        writeLogMessage(tag, INFO, msg);
    }

    /**
     * DEBUG: Information message
     *
     * @param tag the tag characterizing the log message initiator
     * @param msg the message to be logged
     */
    public void debug(String tag, String msg) {
        writeLogMessage(tag, DEBUG, msg);
    }

    /**
     * DEBUG: Information message
     *
     * @param obj the object that send log message
     * @param msg the message to be logged
     */
    public void debug(Object obj, String msg) {
        writeLogMessage(obj.getClass().getName(), DEBUG, msg);
    }

    /**
     * TRACE: Information message
     *
     * @param obj the object that send log message
     * @param msg the message to be logged
     */
    public void trace(Object obj, String msg) {
        writeLogMessage(obj.getClass().getName(), TRACE, msg);
    }

    /**
     * TRACE: Information message
     *
     * @param tag the tag characterizing the log message initiator
     * @param msg the message to be logged
     */
    public void trace(String tag, String msg) {
        writeLogMessage(tag, TRACE, msg);
    }

    /**
     * 打印日志，如果当前设置的输出日志级别
     *
     * @param tag   日志标签
     * @param level 打印的日志级别
     * @param msg   日志文本
     */
    private void writeLogMessage(String tag, int level, String msg) {
        if (level <= this.level) {
            try {
                if (appender != null) {
                    String logMsg = ("[" + android.os.Process.myPid() + " "
                            + android.os.Process.myTid() + "] " + msg);
                    appender.writeLogMessage(tag, stringOf(level), logMsg);
                }
            } catch (Throwable t) {
                String caller = getCaller(new Throwable());
                String className = t.getClass().getSimpleName();
                Log.e(caller, "[" + tag + "][" + level + "][" + msg
                        + "] log failed(" + className + "): " + t.getMessage());
            }
        }
    }

    /**
     * 打印日志，如果当前设置的输出日志级别
     *
     * @param tag   日志标签
     * @param level 打印的日志级别
     * @param msg   日志文本
     * @param t     异常定义
     */
    private void writeLogMessage(String tag, int level, String msg, Throwable t) {
        if (level <= this.level) {
            try {
                if (appender != null) {
                    String logMsg = ("[" + android.os.Process.myPid() + " "
                            + android.os.Process.myTid() + "] " + msg);
                    appender.writeLogMessage(tag, stringOf(level), logMsg, t);
                }
            } catch (Throwable tt) {
                String caller = getCaller(new Throwable());
                String className = t.getClass().getSimpleName();
                Log.e(caller, "[" + tag + "][" + level + "][" + msg
                        + "] log failed(" + className + "): " + tt.getMessage());
            }
        }
    }

    /**
     * 根据日志级别等级转换成字符串
     *
     * @param level 日志级别等级
     * @return 字符串
     */
    private String stringOf(int level) {
        String levelMsg = "";

        switch (level) {
            case DEBUG:
                levelMsg = "DEBUG";
                break;
            case INFO:
                levelMsg = "INFO";
                break;
            case ERROR:
                levelMsg = "ERROR";
                break;
            case TRACE:
                levelMsg = "TRACE";
                break;
            case WARN:
                levelMsg = "WARN";
                break;
            default:
                return "UNKNOWN";
        }

        return levelMsg;
    }

    /**
     * 获取调用者类名
     *
     * @param t 虚构异常对象
     * @return 调用者类名
     */
    private String getCaller(Throwable t) {
        StackTraceElement[] elements = t.getStackTrace();

        if ((null != elements) && (elements.length > 1)) {
            return (elements[1].getClassName()
                    + "$" + elements[1].getMethodName());
        } else {
            return "Unknown Caller";
        }
    }
}
